use rbatis::rbatis::Rbatis;
use crate::pojo::ktv::Ktv;
use rbatis::crud::CRUD;
use rbatis::Error;
use crate::pojo::room::Room;
use chrono::{NaiveDateTime, Local, Duration};
use crate::pojo::daily_room_type::DailyRoomType;
use crate::pojo::set_meal::SetMeal;
use std::collections::HashMap;
use crate::pojo::freight_template::FreightTemplate;
use crate::pojo::commodity_classification::CommodityClassification;
use futures::future::{BoxFuture, FutureExt};
use crate::pojo::{room, set_meal, freight_template, commodity_classification};
use futures::join;

pub struct KtvService{
    pub room :Room,
    pub set_meal: SetMeal,
    pub freight_template: FreightTemplate,
    pub commodity_classification: CommodityClassification,
}

pub async fn new_ktv_service() -> KtvService{
    KtvService{
        room: room::new_room().await,
        set_meal: set_meal::new_set_meal().await,
        freight_template: freight_template::new_freight_template().await,
        commodity_classification: commodity_classification::new_commodity_classification().await
    }
}

impl KtvService{
    pub async fn find_all_ktv(&self, rbatis: &Rbatis) -> Vec<Ktv>{
        // let ks = KtvService{ room: Room {
        //     id: None,
        //     name: None,
        //     ktv_id: None,
        //     capacity: None,
        //     remark: None,
        //     create_time: None,
        //     update_time: None,
        //     version: None,
        //     delete_flag: None,
        //     set_meal_list: None
        // },
        //     set_meal: SetMeal {
        //         id: None,
        //         room_id: None,
        //         name: None,
        //         singing_date: None,
        //         time_frame: None,
        //         time_interval: None,
        //         begin_time: None,
        //         finish_time: None,
        //         remark: None,
        //         create_time: None,
        //         update_time: None,
        //         version: None,
        //         delete_flag: None,
        //         start_time_list: None
        //     },
        //     freight_template: FreightTemplate {
        //         id: None,
        //         billing_rule: None,
        //         province_id: None,
        //         unified_price: None,
        //         regional_price: None,
        //         details: None,
        //         create_time: None,
        //         update_time: None,
        //         delete_flag: None
        //     },
        //     commodity_classification: CommodityClassification {
        //         id: None,
        //         name: None,
        //         parent_id: None,
        //         remark: None,
        //         create_time: None,
        //         update_time: None,
        //         delete_flag: None,
        //         subcategory_list: None
        //     }
        // };
        
        let mut ktv_list :Vec<Ktv> = rbatis.fetch_list().await.unwrap();
        for ktv in &mut ktv_list {
            match &ktv.id {
                Some(ktv_id) =>{
                    let now:NaiveDateTime = Local::now().naive_local();

                    if let Some(appointment_day) = ktv.appointment_day {
                        // if let Some(daily_room_type_list) = &mut ktv.daily_room_type_list {

                        let mut daily_room_type_list :Vec<DailyRoomType> = Vec::new();
                        for i in 1..appointment_day {
                          let mut drt = DailyRoomType{
                                day: Some((now + Duration::days(i as i64)).format("%Y-%m-%d").to_string()),
                                room_list: None
                            };

                            // ks.room.find_all_room
                            if let Ok(mut result_room_list) = self.room.find_all_room(rbatis, ktv_id.to_string()).await {
                                drt.room_list = Some(result_room_list);

                                if let Some(ergodic_room_list) = &mut drt.room_list {
                                    for room in ergodic_room_list {
                                        match &room.id {
                                            Some(room_id) =>{
                                                if let Some(exact_date) = &drt.day {

                                                    // ks.set_meal.find_all_set_meal
                                                    match self.set_meal.find_all_set_meal(rbatis, exact_date, room_id).await {
                                                        Ok(set_meal_list) =>{
                                                            room.set_meal_list = Some(set_meal_list);

                                                            if let Some(room_set_meal_list) = &mut room.set_meal_list {
                                                                for room_set_meal in room_set_meal_list {
                                                                    let mut start_time_list :Vec<HashMap<String, String>> = Vec::new();
                                                                    if let Some(time_frame) = room_set_meal.time_frame {
                                                                        // let end_time = now + Duration::hours(time_frame as i64);
                                                                        match room_set_meal.time_interval {
                                                                            Some(time_interval) => {
                                                                                if let Some(begin_time) = room_set_meal.begin_time {
                                                                                    let mut want_time = begin_time;
                                                                                    if let Some(finish_time) = room_set_meal.finish_time {
                                                                                        loop {
                                                                                            want_time = want_time + Duration::minutes(time_interval as i64);

                                                                                            if want_time.timestamp_millis() > finish_time.timestamp_millis(){
                                                                                                break
                                                                                            }

                                                                                            let mut time_info :HashMap<String, String> = HashMap::new();

                                                                                            time_info.insert("start_time".to_string(), want_time.format("%H:%M:%S").to_string());
                                                                                            if finish_time.timestamp() - want_time.timestamp() < (time_frame as i64) * 3600 {
                                                                                                time_info.insert("remark".to_string(),format!("不足{:?}小时按{:?}小时计算", time_frame, time_frame).to_string());
                                                                                            }else {
                                                                                                time_info.insert("remark".to_string(),"".to_string());
                                                                                            }
                                                                                            start_time_list.push(time_info);

                                                                                            want_time = want_time;
                                                                                        }
                                                                                    }
                                                                                }
                                                                            },
                                                                            _ => {}
                                                                        }
                                                                    }

                                                                    room_set_meal.start_time_list = Some(start_time_list);
                                                                }
                                                            }
                                                        },
                                                        _ => {}
                                                    }
                                                }
                                            },
                                            _ => {}
                                        }
                                    }
                                }
                            }

                            daily_room_type_list.push(drt);
                        }
                        // }

                        ktv.daily_room_type_list = Some(daily_room_type_list);
                    }
                },
                None => {}
            }
        }
        
        ktv_list
    }

    pub async fn query_async(&self, rbatis: &Rbatis, ktv_list: &mut Vec<Ktv>){
        for ktv in ktv_list {
            match &ktv.id {
                Some(ktv_id) =>{
                    let now:NaiveDateTime = Local::now().naive_local();

                    if let Some(appointment_day) = ktv.appointment_day {
                        // if let Some(daily_room_type_list) = &mut ktv.daily_room_type_list {

                        let mut daily_room_type_list :Vec<DailyRoomType> = Vec::new();
                        for i in 1..appointment_day {
                            let mut drt = DailyRoomType{
                                day: Some((now + Duration::days(i as i64)).format("%Y-%m-%d").to_string()),
                                room_list: None
                            };

                            // ks.room.find_all_room
                            if let Ok(mut result_room_list) = self.room.find_all_room(rbatis, ktv_id.to_string()).await {
                                drt.room_list = Some(result_room_list);

                                if let Some(ergodic_room_list) = &mut drt.room_list {
                                    for room in ergodic_room_list {
                                        match &room.id {
                                            Some(room_id) =>{
                                                if let Some(exact_date) = &drt.day {

                                                    // ks.set_meal.find_all_set_meal
                                                    match self.set_meal.find_all_set_meal(rbatis, exact_date, room_id).await {
                                                        Ok(set_meal_list) =>{
                                                            room.set_meal_list = Some(set_meal_list);

                                                            if let Some(room_set_meal_list) = &mut room.set_meal_list {
                                                                for room_set_meal in room_set_meal_list {
                                                                    let mut start_time_list :Vec<HashMap<String, String>> = Vec::new();
                                                                    if let Some(time_frame) = room_set_meal.time_frame {
                                                                        // let end_time = now + Duration::hours(time_frame as i64);
                                                                        match room_set_meal.time_interval {
                                                                            Some(time_interval) => {
                                                                                if let Some(begin_time) = room_set_meal.begin_time {
                                                                                    let mut want_time = begin_time;
                                                                                    if let Some(finish_time) = room_set_meal.finish_time {
                                                                                        loop {
                                                                                            want_time = want_time + Duration::minutes(time_interval as i64);

                                                                                            if want_time.timestamp_millis() > finish_time.timestamp_millis(){
                                                                                                break
                                                                                            }

                                                                                            let mut time_info :HashMap<String, String> = HashMap::new();

                                                                                            time_info.insert("start_time".to_string(), want_time.format("%H:%M:%S").to_string());
                                                                                            if finish_time.timestamp() - want_time.timestamp() < (time_frame as i64) * 3600 {
                                                                                                time_info.insert("remark".to_string(),format!("不足{:?}小时按{:?}小时计算", time_frame, time_frame).to_string());
                                                                                            }else {
                                                                                                time_info.insert("remark".to_string(),"".to_string());
                                                                                            }
                                                                                            start_time_list.push(time_info);

                                                                                            want_time = want_time;
                                                                                        }
                                                                                    }
                                                                                }
                                                                            },
                                                                            _ => {}
                                                                        }
                                                                    }

                                                                    room_set_meal.start_time_list = Some(start_time_list);
                                                                }
                                                            }
                                                        },
                                                        _ => {}
                                                    }
                                                }
                                            },
                                            _ => {}
                                        }
                                    }
                                }
                            }

                            daily_room_type_list.push(drt);
                        }
                        // }

                        ktv.daily_room_type_list = Some(daily_room_type_list);

                    }
                },
                None => {}
            }
        }
    }

    pub async fn find_all_ktv_async(&self, rbatis: &Rbatis) -> Vec<Ktv>{

        let mut ktv_list:Vec<Ktv> = rbatis.fetch_list().await.unwrap();

        let f1 = self.query_async(rbatis, &mut ktv_list);
        // let f2 = self.query_async(rbatis, &mut ktv_list);
        join!(f1);

        ktv_list
    }

    pub async fn inquiry_of_postage(&self, rbatis: &Rbatis, good_id :&String, user_id :&String) -> HashMap<String, String>{
        // let ks = KtvService{ room: Room {
        //     id: None,
        //     name: None,
        //     ktv_id: None,
        //     capacity: None,
        //     remark: None,
        //     create_time: None,
        //     update_time: None,
        //     version: None,
        //     delete_flag: None,
        //     set_meal_list: None
        // },
        //     set_meal: SetMeal {
        //         id: None,
        //         room_id: None,
        //         name: None,
        //         singing_date: None,
        //         time_frame: None,
        //         time_interval: None,
        //         begin_time: None,
        //         finish_time: None,
        //         remark: None,
        //         create_time: None,
        //         update_time: None,
        //         version: None,
        //         delete_flag: None,
        //         start_time_list: None
        //     },
        //     freight_template: FreightTemplate {
        //         id: None,
        //         billing_rule: None,
        //         province_id: None,
        //         unified_price: None,
        //         regional_price: None,
        //         details: None,
        //         create_time: None,
        //         update_time: None,
        //         delete_flag: None
        //     },
        //     commodity_classification: CommodityClassification {
        //         id: None,
        //         name: None,
        //         parent_id: None,
        //         remark: None,
        //         create_time: None,
        //         update_time: None,
        //         delete_flag: None,
        //         subcategory_list: None
        //     }
        // };

        let mut result :HashMap<String, String> = HashMap::new();

        // ks.freight_template.find_freight_info
        if let Ok(freight_info) = self.freight_template.find_freight_info(rbatis, good_id, user_id).await{
            match freight_info.billing_rule {
                Some(billing_rule) =>{
                    if let Some(unified_price) = freight_info.unified_price {
                        if let Some(regional_price) = freight_info.regional_price {
                            if billing_rule == 1{
                                result.insert("express_amount".to_string(), unified_price.to_string());
                            }else if billing_rule == 2{
                                result.insert("express_amount".to_string(), (unified_price + regional_price).to_string());
                            }else if billing_rule == 3{
                                result.insert("express_amount".to_string(), regional_price.to_string());
                            }else if billing_rule == 4{
                                result.insert("express_amount".to_string(), unified_price.to_string());
                            }else{
                                result.insert("express_amount".to_string(), "".to_string());
                            }
                        }
                    }
                },
                _ => {}
            }

            match freight_info.good_id{
                Some(good_id) => {
                    result.insert("good".to_string(), good_id);
                },

                None => {}
            }

            match freight_info.province_id{
                Some(province_id) => {
                    result.insert("city".to_string(), province_id);
                },

                None => {}
            }
        }

        result
    }

    // pub fn query_sub_classification(&self, rbatis :&Rbatis, ks :&KtvService, classification :&mut CommodityClassification) -> BoxFuture<'static, ()>{
    //     async move {
    //         if let Some(id) = &classification.id {
    //             if let Ok(mut subcategory_list) = ks.commodity_classification.find_subcategory_list(rbatis, id).await {
    //                 if !subcategory_list.is_empty() {
    //
    //                     // classification.subcategory_list = Some(subcategory_list);
    //                     // if let Some(second_subcategory_list) = &mut classification.subcategory_list {
    //                     //     for subcategory in second_subcategory_list {
    //                     //         if let Some(sub_parent_id) = &subcategory.id {
    //                     //             self.query_sub_classification(rbatis,  subcategory).await
    //                     //         }
    //                     //     }
    //                     // }
    //
    //                     for subcategory in &mut subcategory_list {
    //                         if let Some(sub_parent_id) = &subcategory.id {
    //                             self.query_sub_classification(rbatis, &ks,subcategory).await
    //                         }
    //                     }
    //
    //                     classification.subcategory_list = Some(subcategory_list);
    //                 }
    //             }
    //         }
    //     }.boxed()
    // }
    //
    // pub async fn query_classification(&self, rbatis :&Rbatis, classification_id :&String) -> Option<CommodityClassification> {
    //     let ks = KtvService{ room: Room {
    //         id: None,
    //         name: None,
    //         ktv_id: None,
    //         capacity: None,
    //         remark: None,
    //         create_time: None,
    //         update_time: None,
    //         version: None,
    //         delete_flag: None,
    //         set_meal_list: None
    //     },
    //         set_meal: SetMeal {
    //             id: None,
    //             room_id: None,
    //             name: None,
    //             singing_date: None,
    //             time_frame: None,
    //             time_interval: None,
    //             begin_time: None,
    //             finish_time: None,
    //             remark: None,
    //             create_time: None,
    //             update_time: None,
    //             version: None,
    //             delete_flag: None,
    //             start_time_list: None
    //         },
    //         freight_template: FreightTemplate {
    //             id: None,
    //             billing_rule: None,
    //             province_id: None,
    //             unified_price: None,
    //             regional_price: None,
    //             details: None,
    //             create_time: None,
    //             update_time: None,
    //             delete_flag: None
    //         },
    //         commodity_classification: CommodityClassification {
    //             id: None,
    //             name: None,
    //             parent_id: None,
    //             remark: None,
    //             create_time: None,
    //             update_time: None,
    //             delete_flag: None,
    //             subcategory_list: None
    //         }
    //     };
    //
    //     if let Ok(mut category) = ks.commodity_classification.find_category(rbatis, classification_id).await {
    //         self.query_sub_classification(rbatis, &ks, &mut category);
    //         Some(category)
    //     }else {
    //         None
    //     }
    // }
}
